﻿using SD.Common;
using SlamDunk.MES.Domain.Entities.ResourceContext;
using SlamDunk.MES.Domain.Entities.StockContext;
using SlamDunk.MES.Domain.IDomainServices;
using SlamDunk.MES.Domain.Mediators;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SlamDunk.MES.DomainService.Implements
{
    /// <summary>
    /// 库存单据领域服务实现
    /// </summary>
    public class StockOrderService : IStockOrderService
    {
        #region # 字段及构造器

        /// <summary>
        /// 仓储中介者
        /// </summary>
        private readonly RepositoryMediator _repMediator;

        /// <summary>
        /// 物料条码领域服务接口
        /// </summary>
        private readonly IMaterialBarcodeService _materialBarcodeSvc;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public StockOrderService(RepositoryMediator repMediator, IMaterialBarcodeService materialBarcodeSvc)
        {
            this._repMediator = repMediator;
            this._materialBarcodeSvc = materialBarcodeSvc;
        }

        #endregion

        #region # 生成库存结转记录 —— ICollection<StockSettlement> GenerateStockSettlements(...
        /// <summary>
        /// 生成库存结转记录
        /// </summary>
        /// <param name="stockOrder">库存单据</param>
        /// <returns>库存结转记录集</returns>
        public ICollection<StockSettlement> GenerateStockSettlements(StockOrder stockOrder)
        {
            IList<StockSettlement> stockSettlements = new List<StockSettlement>();
            if (stockOrder is StockInOrder stockInOrder)
            {
                DateTime settledDate = DateTime.Today;
                foreach (StockOrderDetail detail in stockInOrder.Details)
                {
                    if (!this._repMediator.StockSettlementRep.Exists(detail.MaterialId, detail.MaterialLotId, stockInOrder.TargetStorageLocationType, stockInOrder.TargetStorageLocationId))
                    {
                        StockSettlement stockSettlement = new StockSettlement(detail.MaterialId, detail.MaterialLotId, stockInOrder.TargetStorageLocationType, stockInOrder.TargetStorageLocationId, stockInOrder.TargetStorageLocationName, settledDate, 0m, stockInOrder.FacilityId, "入库单期初");
                        stockSettlements.Add(stockSettlement);
                    }
                }
            }

            return stockSettlements;
        }
        #endregion

        #region # 生成物料条码 —— ICollection<MaterialBarcode> GenerateMaterialBarcodes(...
        /// <summary>
        /// 生成物料条码
        /// </summary>
        /// <param name="stockOrder">库存单据</param>
        /// <returns>物料条码集</returns>
        public ICollection<MaterialBarcode> GenerateMaterialBarcodes(StockOrder stockOrder)
        {
            IList<MaterialBarcode> materialBarcodes = new List<MaterialBarcode>();
            if (stockOrder is StockInOrder stockInOrder && stockInOrder.GenerateBarcode)
            {
                IEnumerable<Guid> materialIds = stockOrder.Details.Select(x => x.MaterialId);
                IEnumerable<Guid> materialLotIds = stockOrder.Details.Where(x => x.MaterialLotId.HasValue).Select(x => x.MaterialLotId.Value);
                IDictionary<Guid, Material> materials = this._repMediator.MaterialRep.Find(materialIds);
                IDictionary<Guid, MaterialLot> materialLots = this._repMediator.MaterialLotRep.Find(materialLotIds);

                foreach (StockOrderDetail detail in stockInOrder.Details)
                {
                    Material material = materials[detail.MaterialId];
                    MaterialLot materialLot = detail.MaterialLotId.HasValue
                        ? materialLots[detail.MaterialLotId.Value]
                        : null;
                    if (material.MaterialBarcodeSetting != null &&
                        material.MaterialBarcodeSetting.NeedPrintBarcode &&
                        material.MaterialBarcodeSetting.BarcodeMode == BarcodeMode.Unique)
                    {
                        //生成条码
                        ICollection<MaterialBarcode> detailRelatedMaterialBarcodes = this._materialBarcodeSvc.GenerateMaterialBarcodes(material, materialLot, detail.Quantity);

                        //库存单据明细关联条码
                        detail.GenerateBarcodes();
                        detail.RelateBarcodes(detailRelatedMaterialBarcodes.Select(x => new StockOrderBarcode(x.Number)));

                        materialBarcodes.AddRange(detailRelatedMaterialBarcodes);
                    }
                }
            }

            return materialBarcodes;
        }
        #endregion

        #region # 生成出/入库记录 —— ICollection<BoundRecord> GenerateBoundRecords(StockOrder stockOrder)
        /// <summary>
        /// 生成出/入库记录
        /// </summary>
        /// <param name="stockOrder">库存单据</param>
        /// <returns>出/入库记录集</returns>
        public ICollection<BoundRecord> GenerateBoundRecords(StockOrder stockOrder)
        {
            IList<BoundRecord> boundRecords = new List<BoundRecord>();
            foreach (StockOrderDetail detail in stockOrder.Details)
            {
                if (stockOrder is StockInOrder stockInOrder)
                {
                    BoundRecord boundRecord = new BoundRecord(detail.MaterialId, detail.MaterialLotId,
                        StockDirectionType.Input, stockInOrder.TargetStorageLocationType,
                        stockInOrder.TargetStorageLocationId, stockInOrder.TargetStorageLocationName,
                        stockOrder.StockOrderClassId, stockOrder.Id, stockOrder.Number, detail.Id, detail.Quantity,
                        stockOrder.FacilityId);

                    //出/入库记录关联条码
                    boundRecord.RelateBarcodes(detail.RelatedBarcodeNos);
                    boundRecords.Add(boundRecord);
                }
                if (stockOrder is StockOutOrder stockOutOrder)
                {
                    BoundRecord boundRecord = new BoundRecord(detail.MaterialId, detail.MaterialLotId, StockDirectionType.Output, stockOutOrder.SourceStorageLocationType, stockOutOrder.SourceStorageLocationId, stockOutOrder.SourceStorageLocationName, stockOrder.StockOrderClassId, stockOrder.Id, stockOrder.Number, detail.Id, detail.Quantity, stockOrder.FacilityId);

                    //出/入库记录关联条码
                    boundRecord.RelateBarcodes(detail.RelatedBarcodeNos);
                    boundRecords.Add(boundRecord);
                }
            }

            return boundRecords;
        }
        #endregion
    }
}
